"""
UI优化工具模块
提供UI响应性优化功能，包括异步加载、缓存、虚拟化等
"""

import threading
import time
from typing import Any, Callable, Dict, List, Optional, Tuple
import tkinter as tk
from tkinter import ttk, messagebox
from core.utils.logger import debug, info, warning, error
from core.utils.error_handler import ErrorHandler


class LoadingIndicator:
    """加载指示器"""
    
    def __init__(self, parent, text="Loading..."):
        self.parent = parent
        self.text = text
        self.frame = None
        self.progress = None
        self.label = None
        self.is_visible = False
    
    def show(self):
        """显示加载指示器"""
        if self.is_visible:
            return
        
        self.is_visible = True
        self.frame = ttk.Frame(self.parent)
        self.frame.place(relx=0.5, rely=0.5, anchor='center')
        
        # 加载标签
        self.label = ttk.Label(
            self.frame, 
            text=self.text,
            font=('Arial', 12),
            foreground='#666666'
        )
        self.label.pack(pady=10)
        
        # 进度条
        self.progress = ttk.Progressbar(
            self.frame,
            mode='indeterminate',
            length=200
        )
        self.progress.pack(pady=5)
        self.progress.start()
        
        # 强制更新界面
        self.parent.update()
    
    def hide(self):
        """隐藏加载指示器"""
        if not self.is_visible:
            return
        
        self.is_visible = False
        if self.frame:
            self.frame.destroy()
            self.frame = None
            self.progress = None
            self.label = None


class ImageCache:
    """图片缓存管理器"""
    
    def __init__(self, max_size=200):
        self.cache: Dict[str, Any] = {}
        self.max_size = max_size
        self.access_order: List[str] = []
    
    def get(self, key: str) -> Optional[Any]:
        """获取缓存的图片"""
        if key in self.cache:
            # 更新访问顺序
            if key in self.access_order:
                self.access_order.remove(key)
            self.access_order.append(key)
            return self.cache[key]
        return None
    
    def set(self, key: str, value: Any):
        """设置缓存的图片"""
        # 如果缓存已满，删除最久未使用的项
        if len(self.cache) >= self.max_size and key not in self.cache:
            oldest_key = self.access_order.pop(0)
            del self.cache[oldest_key]
        
        self.cache[key] = value
        if key in self.access_order:
            self.access_order.remove(key)
        self.access_order.append(key)
    
    def clear(self):
        """清空缓存"""
        self.cache.clear()
        self.access_order.clear()


class AsyncLoader:
    """异步加载器"""
    
    def __init__(self):
        self.loading_indicators: Dict[str, LoadingIndicator] = {}
        self.image_cache = ImageCache()
    
    def load_async(self, parent, operation: Callable, callback: Callable, 
                   loading_text: str = "Loading...", operation_id: str = None):
        """异步执行操作"""
        if operation_id is None:
            operation_id = f"op_{int(time.time() * 1000)}"
        
        # 显示加载指示器
        indicator = LoadingIndicator(parent, loading_text)
        self.loading_indicators[operation_id] = indicator
        indicator.show()
        
        def worker():
            try:
                result = operation()
                # 在主线程中执行回调
                parent.after(0, lambda: self._execute_callback(parent, callback, result, operation_id))
            except Exception as e:
                error(f"异步操作失败: {str(e)}")
                parent.after(0, lambda: self._execute_callback(parent, callback, None, operation_id, e))
        
        # 启动工作线程
        thread = threading.Thread(target=worker, daemon=True)
        thread.start()
    
    def _execute_callback(self, parent, callback: Callable, result: Any, 
                         operation_id: str, error: Exception = None):
        """执行回调函数"""
        # 隐藏加载指示器
        if operation_id in self.loading_indicators:
            self.loading_indicators[operation_id].hide()
            del self.loading_indicators[operation_id]
        
        # 执行回调
        try:
            if error:
                callback(None, error)
            else:
                callback(result, None)
        except Exception as e:
            ErrorHandler.log_exception(e, f"执行回调函数 {callback.__name__}")
    
    def load_image_async(self, parent, image_path: str, size: Tuple[int, int], 
                        callback: Callable, loading_text: str = "Loading image..."):
        """异步加载图片"""
        cache_key = f"{image_path}_{size[0]}x{size[1]}"
        
        # 检查缓存
        cached_image = self.image_cache.get(cache_key)
        if cached_image:
            parent.after(0, lambda: callback(cached_image, None))
            return
        
        def load_image():
            try:
                from core.utils.image_utils import load_thumbnail
                return load_thumbnail(image_path, size=size)
            except Exception as e:
                raise e
        
        def on_image_loaded(image, error):
            if image and not error:
                # 缓存图片
                self.image_cache.set(cache_key, image)
            callback(image, error)
        
        self.load_async(parent, load_image, on_image_loaded, loading_text)


class VirtualList:
    """虚拟列表组件 - 只渲染可见项目"""
    
    def __init__(self, parent, item_height=100, visible_items=10):
        self.parent = parent
        self.item_height = item_height
        self.visible_items = visible_items
        self.data: List[Any] = []
        self.render_start = 0
        self.render_end = 0
        self.scroll_position = 0
        self.item_renderer: Optional[Callable] = None
        self.container = None
        self.scrollbar = None
        self._setup_ui()


class VirtualGrid:
    """虚拟网格组件 - 只渲染可见区域的商品"""
    
    def __init__(self, parent, columns=4, row_height=300):
        self.parent = parent
        self.columns = columns
        self.row_height = row_height
        self.data: List[Any] = []
        self.item_renderer: Optional[Callable] = None
        self.container = None
        self.visible_items = []
        self._setup_ui()
    
    def _setup_ui(self):
        """设置UI组件"""
        self.container = tk.Frame(self.parent)
        self.container.pack(fill='both', expand=True)
        
        # 创建滚动条
        self.scrollbar = ttk.Scrollbar(self.container, orient='vertical')
        self.scrollbar.pack(side='right', fill='y')
        
        # 创建画布用于检测滚动
        self.canvas = tk.Canvas(
            self.container,
            yscrollcommand=self.scrollbar.set,
            highlightthickness=0
        )
        self.canvas.pack(side='left', fill='both', expand=True)
        self.scrollbar.config(command=self.canvas.yview)
        
        # 绑定滚动事件
        self.canvas.bind('<MouseWheel>', self._on_scroll)
        self.canvas.bind('<Button-4>', self._on_scroll)
        self.canvas.bind('<Button-5>', self._on_scroll)
    
    def set_data(self, data: List[Any], item_renderer: Callable):
        """设置数据和渲染器"""
        self.data = data
        self.item_renderer = item_renderer
        self._update_display()
    
    def _on_scroll(self, event):
        """处理滚动事件"""
        if event.delta:
            delta = -1 if event.delta > 0 else 1
        else:
            delta = -1 if event.num == 4 else 1
        
        self.canvas.yview_scroll(int(delta), "units")
        self._update_display()
    
    def _update_display(self):
        """更新显示"""
        if not self.data or not self.item_renderer:
            return
        
        # 清空当前可见项
        for item in self.visible_items:
            if hasattr(item, 'destroy'):
                item.destroy()
        self.visible_items.clear()
        
        # 获取画布尺寸
        canvas_width = self.canvas.winfo_width()
        if canvas_width <= 1:
            return
        
        # 计算可见区域
        y1 = self.canvas.canvasy(0)
        y2 = self.canvas.canvasy(self.canvas.winfo_height())
        
        # 计算可见行范围
        start_row = max(0, int(y1 // self.row_height) - 1)
        end_row = min(
            int(y2 // self.row_height) + 2,
            (len(self.data) + self.columns - 1) // self.columns
        )
        
        # 创建网格框架
        grid_frame = ttk.Frame(self.parent)
        
        # 渲染可见商品
        for row in range(start_row, end_row):
            for col in range(self.columns):
                idx = row * self.columns + col
                if idx >= len(self.data):
                    break
                
                product = self.data[idx]
                item = self.item_renderer(product, grid_frame)
                if item:
                    item.grid(row=row, column=col, padx=5, pady=5, sticky='nsew')
                    self.visible_items.append(item)
        
        # 更新滚动区域
        total_rows = (len(self.data) + self.columns - 1) // self.columns
        total_height = total_rows * self.row_height + 100
        self.canvas.config(scrollregion=(0, 0, canvas_width, total_height))


class UIOptimizer:
    """UI优化器主类"""
    
    def __init__(self):
        self.async_loader = AsyncLoader()
        self.image_cache = ImageCache()
        self.virtual_lists: Dict[str, VirtualList] = {}
        self.virtual_grids: Dict[str, VirtualGrid] = {}
    
    def optimize_product_loading(self, parent, products: List[Any], 
                                render_callback: Callable, 
                                batch_size: int = 10):
        """优化商品加载 - 分批渲染"""
        def load_products_batch():
            # 分批渲染商品
            for i in range(0, len(products), batch_size):
                batch = products[i:i + batch_size]
                parent.after(0, lambda b=batch: render_callback(b))
                time.sleep(0.05)  # 增加延迟，让UI有更多时间响应
            return products
        
        self.async_loader.load_async(
            parent, 
            load_products_batch, 
            lambda result, error: None,
            "Loading products..."
        )
    
    def optimize_image_loading(self, parent, image_path: str, size: Tuple[int, int], 
                              callback: Callable):
        """优化图片加载 - 异步+缓存"""
        self.async_loader.load_image_async(parent, image_path, size, callback)
    
    def create_virtual_list(self, parent, list_id: str, item_height: int = 100, 
                           visible_items: int = 10) -> VirtualList:
        """创建虚拟列表"""
        virtual_list = VirtualList(parent, item_height, visible_items)
        self.virtual_lists[list_id] = virtual_list
        return virtual_list
    
    def create_virtual_grid(self, parent, grid_id: str, columns: int = 4, 
                           row_height: int = 300) -> VirtualGrid:
        """创建虚拟网格"""
        virtual_grid = VirtualGrid(parent, columns, row_height)
        self.virtual_grids[grid_id] = virtual_grid
        return virtual_grid
    
    def show_loading_overlay(self, parent, text: str = "Loading..."):
        """显示加载覆盖层"""
        overlay = tk.Frame(parent, bg='white', relief='solid', bd=1)
        overlay.place(relx=0, rely=0, relwidth=1, relheight=1)
        
        # 加载指示器
        indicator = LoadingIndicator(overlay, text)
        indicator.show()
        
        return overlay
    
    def hide_loading_overlay(self, overlay):
        """隐藏加载覆盖层"""
        if overlay:
            overlay.destroy()
    
    def debounce(self, func: Callable, delay: float = 0.3):
        """防抖装饰器 - 延迟执行函数"""
        def debounced(*args, **kwargs):
            if hasattr(debounced, 'timer'):
                debounced.timer.cancel()
            
            def call_func():
                func(*args, **kwargs)
            
            debounced.timer = threading.Timer(delay, call_func)
            debounced.timer.start()
        
        return debounced


# 全局UI优化器实例
ui_optimizer = UIOptimizer()


# 便捷函数
def load_products_async(parent, products: List[Any], render_callback: Callable, 
                       batch_size: int = 10):
    """异步加载商品"""
    ui_optimizer.optimize_product_loading(parent, products, render_callback, batch_size)


def load_image_async(parent, image_path: str, size: Tuple[int, int], callback: Callable):
    """异步加载图片"""
    ui_optimizer.optimize_image_loading(parent, image_path, size, callback)


def create_virtual_list(parent, list_id: str, item_height: int = 100, 
                       visible_items: int = 10) -> VirtualList:
    """创建虚拟列表"""
    return ui_optimizer.create_virtual_list(parent, list_id, item_height, visible_items)


def create_virtual_grid(parent, grid_id: str, columns: int = 4, 
                       row_height: int = 300) -> VirtualGrid:
    """创建虚拟网格"""
    return ui_optimizer.create_virtual_grid(parent, grid_id, columns, row_height)


def show_loading(parent, text: str = "Loading..."):
    """显示加载指示器"""
    return ui_optimizer.show_loading_overlay(parent, text)


def hide_loading(overlay):
    """隐藏加载指示器"""
    ui_optimizer.hide_loading_overlay(overlay)
